home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / progjour / 1988 / 02 / tsr.c < prev    next >
Text File  |  1988-02-18  |  11KB  |  257 lines

  1. Code from "Converting a Turbo C Program to a TSR' by Michael J.
  2. Young, PJ, Volume 6.2.  Copyright 1987 Michael J. Young.
  3.  
  4. Listing 1
  5.  
  6. #pragma inline
  7.  
  8. #include <dos.h>
  9. #include "tsr.h"
  10.  
  11. static unsigned int TCSS;                    /* Turbo C stack segment.      */
  12. static unsigned int TCSP;                    /* Turbo C stack pointer.      */
  13. static void (*UserRtn) (void);     /* Pointer to user's start routine.      */
  14. static int HotKeyMask;             /* Hot key shift mask.                   */
  15. static unsigned int TCDtaSeg;      /* Turbo C Disk Transfer Area segment.   */
  16. static unsigned int TCDtaOff;      /* Turbo C Disk Transfer Area offset.    */
  17. static char far *InDosPtr;         /* Pointer to DOS 'indos' flag.          */
  18. static void interrupt (*OldInt28) (void);    /* Old int 28h vector.         */
  19. static void interrupt (*OldInt13) (void);    /* Old int 13h vector.         */
  20. static void interrupt (*OldInt9) (void);     /* Old int 09h vector.         */
  21. static void interrupt NewInt28 (void);       /* New int 28h handler.        */
  22.                                              /* New int 13h handler:        */
  23. static void interrupt NewInt13  (unsigned BP, unsigned DI, unsigned SI,
  24.                                  unsigned DS, unsigned ES, unsigned DX,
  25.                                  unsigned CX, unsigned BX, unsigned AX,
  26.                                  unsigned IP, unsigned CS, unsigned FLAGS);
  27. static void interrupt NewInt9 (void);        /* New int 09h handler.        */
  28. static int GetShift (void);        /* Returns BIOS shift status flag.       */
  29. static int Busy = 0;               /* Flag indicates TSR is active.         */
  30. static void Activate (void);       /* Routine to activate user's TSR.       */
  31. static int InBios = 0;             /* Flag indicating BIOS disk activity.   */
  32. extern void far *_heapbase;        /* Defined by Turbo C;  holds break addr.*/
  33.  
  34. int TsrInstall (void (*FPtr) (void),int HotKey,VIFP Code)
  35. /*
  36.      This routine terminates the C program, but leaves the code resident in
  37.      memory.  It installs interrupt handlers so that when the shift key
  38.      combination specified by 'HotKey' is pressed, the function pointed to
  39.      by 'FPtr' receives control, provided that conditions are safe.
  40. */
  41.      {
  42.      unsigned int i;
  43.      int Found = 0;
  44.  
  45.      for (i=0x60;i<=0x67;++i)           /* Search 'user' interrupt vectors  */
  46.           if (getvect (i) == Code)      /* to see if Code is present        */
  47.                {                        /* indicating that the TSR is       */
  48.                Found = 1;               /* already installed.               */
  49.                break;
  50.                }
  51.      if (Found)                         /* Already installed, therefore     */
  52.           return (INSTALLED);           /* return error message.            */
  53.      for (i=0x60;i<=0x67;++i)           /* Not already installed, therefore */
  54.           if (getvect (i) == (VIFP)0)   /* search for a free (==0) user     */
  55.                {                        /* interrupt vector.                */
  56.                setvect (i,Code);        /* Found a free vector;  therefore  */
  57.                Found = 1;               /* place special code in vector.    */
  58.                break;
  59.                }
  60.      if (!Found)                        /* No free vectors;  therefore      */
  61.           return (NOINT);               /* return error code.               */
  62.  
  63.      if (_osmajor < 2)                  /* Test that OS version is >= 2.0.  */
  64.           return (WRONGDOS);            /* Wrong DOS version.               */
  65.  
  66.      TCSS = _SS;                        /* Save Turbo C stack segment.      */
  67.      TCSP = _BP;                        /* Save Turbo C stack pointer.      */
  68.      HotKeyMask = HotKey;               /* Save hotkey shift mask.          */
  69.      UserRtn = FPtr;     /* Save address of the routine that is activated   */
  70.                          /* when the hotkey is pressed.                     */
  71.      _AH = 0x2f;                        /* Save old Disk Transfer Address.  */
  72.      geninterrupt (0x21);               /* Invoke MS-DOS function to get    */
  73.      TCDtaSeg = _ES;                    /* current Disk Transfer Address.   */
  74.      TCDtaOff = _BX;
  75.  
  76.      _AH = 0x34;                        /* Get pointer to 'indos' flag using*/
  77.      geninterrupt (0x21);               /* the undocumented function 34h.   */
  78.      InDosPtr = MK_FP (_ES,_BX);
  79.  
  80.      OldInt28 = getvect (0x28);         /* Save old interrupt vectors.      */
  81.      OldInt13 = getvect (0x13);
  82.      OldInt9 = getvect (0x9);
  83.  
  84.      setvect (0x28,NewInt28);           /* Initialize new interrupt vectors.*/
  85.      setvect (0x13,NewInt13);
  86.      setvect (0x9,NewInt9);
  87.  
  88.      keep (0, FP_SEG (_heapbase)-_psp); /* Terminate and stay resident.     */
  89.  
  90.      return (ERROR);                    /* 'keep' should not return,        */
  91.                                         /* therefore something has gone     */
  92.                                         /* wrong.  Return general error code*/
  93.      } /* end TsrInstall */
  94.  
  95.  
  96. static void interrupt NewInt28 (void)
  97. /*
  98.      This is the new interrupt 28, the 'DOS idle interrupt', handler.
  99. */
  100.      {
  101.      (*OldInt28) ();          /* Chain to previous interrupt 28 handler.    */
  102.      disable ();              /* Disable interrupts to test and set         */
  103.      if (Busy)                /* 'Busy' semaphore.                          */
  104.           return;
  105.      Busy = 1;
  106.      enable ();               /* Re-enable interrupts.                      */
  107.      if ((GetShift () & HotKeyMask) != HotKeyMask)     /* Test if hot key   */
  108.           {                                            /* is pressed.       */
  109.           Busy = 0;
  110.           return;
  111.           }
  112.      if (InBios)              /* Test if BIOS disk services is active.      */
  113.           {
  114.           Busy = 0;
  115.           return;
  116.           }
  117.      Activate ();             /* Conditions are safe, therefore activate TSR*/
  118.      Busy = 0;                /* Reset the active semaphore.                */
  119.      return;
  120.                               
  121.      } /* end NewInt28 */
  122.  
  123.  
  124. static void interrupt NewInt13 ( unsigned BP, unsigned DI, unsigned SI,
  125.                                  unsigned DS, unsigned ES, unsigned DX,
  126.                                  unsigned CX, unsigned BX, unsigned AX,
  127.                                  unsigned IP, unsigned CS, unsigned FLAGS)
  128. /*
  129.      This is the new interrupt 13, BIOS disk services, handler.  This
  130.      function serves only to set a flag while BIOS interrupt 13h is active.
  131. */
  132.      {
  133.      ++InBios;                /* Set flag.                                  */
  134.      (*OldInt13) ();          /* Chain to old interrupt 13h handler.        */
  135.      --InBios;                /* Reset flag.                                */
  136.      AX = _AX;                /* Must pass on the information returned by   */
  137.      asm pushf                /* the BIOS in AX and flag registers.         */
  138.      asm pop FLAGS
  139.  
  140.      } /* end NewInt13 */
  141.  
  142.  
  143. static void interrupt NewInt9 (void)
  144. /*
  145.      This is the new handler for interrupt 09, the hardware interrupt
  146.      activated by the keyboard.
  147. */
  148.      {
  149.      (*OldInt9) ();      /* Chain to prior interrupt 09 handler.            */
  150.      disable ();         /* Disable interrupts to test and set 'Busy'       */
  151.      if (Busy)           /* semaphore.                                      */
  152.           return;
  153.      Busy = 1;
  154.      enable ();          /* Enable interrupts.                              */
  155.      if ((GetShift () & HotKeyMask) != HotKeyMask)     /* Test if hot key   */
  156.           {                                            /* is pressed.       */
  157.           Busy = 0;
  158.           return;
  159.           }
  160.      if (InBios || *InDosPtr)      /* Test if EITHER DOS or the BIOS disk   */
  161.           {                        /* services are active.                  */
  162.           Busy = 0;
  163.           return;
  164.           }
  165.      Activate ();             /* Conditions are safe, therefore activate TSR*/
  166.      Busy = 0;                /* Reset the active semaphore.                */
  167.      return;
  168.  
  169.      } /* end NewInt9 */
  170.  
  171.  
  172. static unsigned int OldSS;
  173. static unsigned int OldSP;
  174. static unsigned int OldPsp;
  175. static unsigned int OldDtaSeg;
  176. static unsigned int OldDtaOff;
  177.  
  178. static void Activate (void)
  179. /*
  180.      This function is called either by 'NewInt9' or by 'NewInt29', when
  181.      conditions are safe, to activate the user's TSR entry routine.  
  182. */
  183.      {
  184.      register int DSSave;     /* Temporary storage for C data segment.      */
  185.  
  186.      OldSS = _SS;             /* Switch to Turbo C's own stack.             */
  187.      OldSP = _SP;
  188.      _SS = TCSS;
  189.      _SP = TCSP;
  190.  
  191.      _AH = 0x2f;                        /* Save old Disk Transfer Address.  */
  192.      geninterrupt (0x21);
  193.      OldDtaSeg = _ES;
  194.      OldDtaOff = _BX;
  195.  
  196.      _DX = TCDtaOff;                    /* Set Turbo C Disk Transfer Address*/
  197.      DSSave = _DS;
  198.      _DS = TCDtaSeg;
  199.      _AH = 0x1a;                        /* DOS set DTA service.             */
  200.      geninterrupt (0x21);
  201.      _DS = DSSave;
  202.  
  203.      if (!*InDosPtr)                    /* Save the old PSP and set the PSP */
  204.           {                             /* to the Turbo C value, using the  */
  205.           _AH = 0x51;                   /* undocumented functions 51h and   */
  206.           geninterrupt (0x21);          /* 50h.  Note that this procedure   */
  207.           OldPsp = _BX;                 /* is safe only if DOS is not       */
  208.           _BX = _psp;                   /* active.                          */
  209.           _AH = 0x50;
  210.           geninterrupt (0x21);
  211.           }
  212.     
  213.      (*UserRtn) ();                     /* Call the user's Turbo C function.*/
  214.  
  215.      if (!*InDosPtr)                    /* Restore the PSP, if DOS is not   */
  216.           {                             /* active.                          */
  217.           _BX = OldPsp;
  218.           _AH = 0x50;
  219.           geninterrupt (0x21);
  220.           }
  221.  
  222.      _DX = OldDtaOff;                   /* Restore Old Disk Transfer Address*/
  223.      DSSave = _DS;
  224.      _DS = OldDtaSeg;
  225.      _AH = 0x1a;
  226.      geninterrupt (0x21);
  227.      _DS = DSSave;
  228.  
  229.      _SS = OldSS;                       /* Restore the old stack.           */
  230.      _SP = OldSP;
  231.      return;
  232.  
  233.      } /* end Activate */
  234.  
  235.  
  236. int TsrInDos ()
  237. /*
  238.      This function returns zero if DOS is not currently active, and a
  239.      non-zero value otherwise.
  240. */
  241.      {
  242.      return (*InDosPtr);      /* Uses the 'indos' flag maintained by DOS.   */
  243.  
  244.      } /* end TsrInDos */
  245.  
  246.  
  247. int GetShift ()
  248. /*
  249.      This function returns the BIOS shift status word.
  250. */
  251.      {
  252.      return *((int far *)0x00400017);
  253.  
  254.      } /* end GetShift */
  255.  
  256.  
  257.